<?php
/**
 *      [迷你云] (C)2009-2012 南京恒为网络科技.
 *   软件仅供研究与学习使用，如需商用，请访问www.miniyun.cn获得授权
 * 
 */
?>
<?php

class MFilesCommon extends MModel {
    
    public static function initMFilesCommon() {
                                $overwrite = true;         $locale = "bytes";                                                 $parent_rev = 0;
        if (isset ( $_REQUEST ["locale"] )) {
            $locale = $_REQUEST ["locale"];
        }
        if (isset ( $_REQUEST ["overwrite"] )) {
            $overwrite = $_REQUEST ["overwrite"];
            if (is_string ( $overwrite ) === true) {
                if (strtolower ( $overwrite ) === "false") {
                    $overwrite = false;
                } elseif (strtolower ( $overwrite ) === "true") {
                    $overwrite = true;
                }
            }
        }
        if (isset ( $_REQUEST ["parent_rev"] )) {
            $parent_rev = $_REQUEST ["parent_rev"];
        }
        $user        = MUserManager::getInstance ()->getCurrentUser ();
        $device      = MUserManager::getInstance ()->getCurrentDevice ();
        $file_common                   = new MFilesCommon ();
        $file_common->overwrite        = $overwrite;
        $file_common->locale           = $locale;
        $file_common->parent_rev       = $parent_rev;
        $file_common->user_id          = $user->user_id;
        $file_common->user_nick        = $user->user_name;
        $file_common->user_device_id   = $device->device_id;
        $file_common->action           = MConst::CREATE_FILE;
        $file_common->file_update_time = time();
        $file_common->conflict         = false;         $file_common->space            = MActionFilter::handleGetUserSpace($user->user_id);
        $file_common->used_space       = MActionFilter::handleGetUsedSapce($user->user_id);
        return $file_common;
    }
    
    public function saveFile($tmp_name, $signature, $size, $move = true) {
                                $store_path = DOCUMENT_ROOT_BLOCK . MUtils::getPathBySplitStr ( $signature );
        if (file_exists ( dirname ( $store_path ) ) === false) {
            MUtils::MkDirs ( dirname ( $store_path ) );
        }
        $file_version = MFileVersions::queryFileVersionBySignatrue ( $signature );
        if ($file_version != false && count ( $file_version ) != 0) {
                                                $this->version_id = $file_version [0] ["id"];
            $this->file_hash  = $file_version [0] ["file_signature"];
            if (file_exists ( $store_path ) == false) {
                if (move_uploaded_file ( $tmp_name, $store_path ) == false) {
                    throw new MFilesException ( FXP::t ( MConst::INTERNAL_SERVER_ERROR ), MConst::HTTP_CODE_500 );
                }
            }
            if ($move === true) {
                unlink($tmp_name);
            }
            return;
        }
                                if ($move === true) {
            if (move_uploaded_file ( $tmp_name, $store_path ) == false) {
                throw new MFilesException ( FXP::t ( MConst::INTERNAL_SERVER_ERROR ), MConst::HTTP_CODE_500 );
            }
        }
                                if (MFileVersions::createFileVersion ( $signature, $size, $this->type ) == false) {
            throw new MFilesException ( FXP::t ( MConst::INTERNAL_SERVER_ERROR ), MConst::HTTP_CODE_500 );
            ;
        }
                                $file_version = MFileVersions::queryFileVersionBySignatrue ( $signature );
        if ($file_version == false || count ( $file_version ) == 0) {
            throw new MFilesException ( FXP::t ( MConst::INTERNAL_SERVER_ERROR ), MConst::HTTP_CODE_500 );
        }
                                $this->version_id = $file_version [0] ["id"];
        $this->file_hash  = $file_version [0] ["file_signature"];
    }
    
    public function SaveFileDetails() {
                                if (MUtils::checkNameInvalid($this->file_name))
        {
            throw new MFileopsException(FXP::t('bad request'), MConst::HTTP_CODE_400);
        }
                                $parent_check_handler = new MCreateFolderController();
        $parent_check_handler->_user_id           = $this->user_id;
        $parent_check_handler->_user_device_id = $this->user_device_id;
        $this->parent_file_id = $parent_check_handler->handlerParentFolder("/" . $this->user_id . $this->parent_path);
        
                                $this->file_path = "/" . $this->user_id . $this->path;
                                $file_detail = MFiles::queryFilesByPath ( $this->file_path );
        $this->create_file = false;
        if ($file_detail == false || count ( $file_detail ) == 0) {             $this->create_file = true;
            $file_detail = new MFiles ();
        } else {             $file_detail = MFiles::exchange2Object ( $file_detail );
                                                if ($file_detail->file_type != MConst::OBJECT_TYPE_FILE) {
                throw new MFilesException ( FXP::t ( "There is already a folder at the given destination" ), MConst::HTTP_CODE_403 );
            }
        } 
        $this->modifyFile ( $file_detail );
        if (isset($file_detail->is_deleted)) {
            $this->spaceFilter ($this->size - $file_detail->file_size);           }
        
        $this->conflictFile ();
        $this->renameFile ();
        $this->createFile ( $file_detail );
        $this->success = true;
    }
    
    public function buildResult() {
        if (! isset ( $this->success ) || $this->success != true) {
            throw new MFilesException ( FXP::t ( MConst::INTERNAL_SERVER_ERROR ), MConst::HTTP_CODE_500 );
        }
        $response = array ();
        $response ["size"] = MUtils::getSizeByLocale ( $this->locale, $this->size );
        $response ["rev"] = $this->version_id;
        $response ["thumb_exists"] = $this->isExistThumbnail ();
        $response ["bytes"] = $this->size;
        $response ["modified"] = MUtils::formatIntTime($this->file_update_time);
        $response ["path"] = MUtils::convertStandardPath ( dirname ( $this->path ) . "/" . $this->file_name );
        $response ["is_dir"] = false;
        $response ["icon"] = "file";
        $response ["root"] = $this->root;
        $response ["mime_type"] = $this->type;
        $response ["revision"] = intval($this->version_id);         $response ["hash"]    = $this->file_hash;         echo json_encode ( $response );
    }
    
    private function creatFileDeleted($file_detail) {
                                if ($this->create_file == false) {
            return;
        }
                                        if ($file_detail->file_type != MConst::OBJECT_TYPE_FILE) {
            throw new MFilesException ( FXP::t ( MConst::INTERNAL_SERVER_ERROR ), MConst::HTTP_CODE_500 );
        }
        $file_meta = MFileMetas::queryFileMeta ( $file_detail->file_path, MConst::VERSION );
        if ($file_meta == false || empty ( $file_meta )) {
            throw new MFilesException ( FXP::t ( MConst::INTERNAL_SERVER_ERROR ), MConst::HTTP_CODE_500 );
        }
        
                                $size_diff = $this->size - $file_detail->file_size;
        $this->spaceFilter($size_diff);
        
        $this->action = MConst::CREATE_FILE;
                                $version = MUtils::getFileVersions ( $this->version_id, $this->action, $this->user_id, $this->user_nick, $file_meta [0] ["meta_value"] );
                                $updates = array ();
        $updates ["version_id"] = ( int ) $this->version_id;
        $updates ["file_size"] = $this->size;
        $updates ["file_update_time"] = $this->file_update_time;
        $updates ["is_deleted"] = 0;
        $updates ["event_uuid"] = MUtils::random_string ( MConst::LEN_EVENT_UUID );
        
        
                                if (MFiles::updateFileDetailById ( $file_detail->id, $updates ) === false) {
            throw new MFilesException ( FXP::t ( MConst::INTERNAL_SERVER_ERROR ), MConst::HTTP_CODE_500 );
        }
                                $context = array( "hash"  => $this->file_hash,
                          "rev"   => (int)$this->version_id,
                          "bytes" => (int)$this->size);
        $retval = MEvents::CreateEvents (  $this->user_id, 
                                           $this->user_device_id, 
                                           $this->action, 
                                           $this->file_path,
                                           serialize($context),
                                           $updates ["event_uuid"] );
        if ($retval === false) {
            throw new MFilesException ( FXP::t ( MConst::INTERNAL_SERVER_ERROR ), MConst::HTTP_CODE_500 );
        }
        if ($this->version_id != $file_detail->version_id) {
                        if (MFileVersions::updateRefCountById ( $this->version_id ) == false) {
                throw new MFilesException ( FXP::t ( MConst::INTERNAL_SERVER_ERROR ), MConst::HTTP_CODE_500 );
            }
                        if (MFileMetas::updateFileMeta ( $this->file_path, MConst::VERSION, $version ) == false) {
                throw new MFilesException ( FXP::t ( MConst::INTERNAL_SERVER_ERROR ), MConst::HTTP_CODE_500 );
            }
        } 
    }
    
    private function modifyFile($file_detail) {
                if ($this->overwrite == false) {
            $this->create_file = true;
            return;
        }
                                if ($this->create_file == true) {
            return;
        }

        $file_meta = MFileMetas::queryFileMeta ( $file_detail->file_path, MConst::VERSION );
        if ($file_meta == false || empty ( $file_meta )) {
            throw new MFilesException ( FXP::t ( MConst::INTERNAL_SERVER_ERROR ), MConst::HTTP_CODE_500 );
        }
                                if (MUtils::isExistReversion ( $this->parent_rev, $file_meta [0] ["meta_value"] ) == false) {
            throw new MFilesException ( FXP::t ( "The revision dosen't exist." ), MConst::HTTP_CODE_404 );
        }
        
                                if ($this->version_id == $file_detail->version_id) {
            return;
        }
                                if ($file_detail->version_id != $this->parent_rev && $this->parent_rev != 0) {
            $this->conflict = true;
            $this->create_file = true;
            return;
        }
        
                                $size_diff = $this->size - $file_detail->file_size;
        $this->spaceFilter($size_diff);
                                $this->action = MConst::MODIFY_FILE;
                                $version = MUtils::getFileVersions ( $this->version_id, $this->action, $this->user_id, $this->user_nick, $file_meta [0] ["meta_value"] );
        
                                $updates = array ();
        $updates ["version_id"] = ( int ) $this->version_id;
        $updates ["file_size"]  = $this->size;
        $updates ["file_update_time"] = $this->file_update_time;
        $updates ["event_uuid"] = MUtils::random_string ( MConst::LEN_EVENT_UUID );
                                if (MFiles::updateFileDetailById ( $file_detail->id, $updates ) === false) {
            throw new MFilesException ( FXP::t ( MConst::INTERNAL_SERVER_ERROR ), MConst::HTTP_CODE_500 );
        }
                                $context = array( 
                  "hash"  => $this->file_hash,
                  "rev"   => (int)$this->version_id,
                  "bytes" => (int)$this->size);
        $retval = MEvents::CreateEvents ( $this->user_id,
                                          $this->user_device_id, 
                                          $this->action,
                                          $file_detail->file_path,
                                          serialize($context), 
                                          $updates ["event_uuid"] );
        if ($retval === false) {
            throw new MFilesException ( FXP::t ( MConst::INTERNAL_SERVER_ERROR ), MConst::HTTP_CODE_500 );
        }
                if (MFileVersions::updateRefCountById ( $this->version_id ) == false) {
            throw new MFilesException ( FXP::t ( MConst::INTERNAL_SERVER_ERROR ), MConst::HTTP_CODE_500 );
        }
                if (MFileMetas::updateFileMeta ( $file_detail->file_path, MConst::VERSION, $version ) == false) {
            throw new MFilesException ( FXP::t ( MConst::INTERNAL_SERVER_ERROR ), MConst::HTTP_CODE_500 );
        }
    }
    
    private function conflictFile() {
        if ($this->conflict == false) {
            return;
        }
                                $paths = MUtils::pathinfo_utf ( $this->file_name );
        $base_name = $paths ["filename"];
        $extension = $paths ["extension"];
        if (is_null ( $extension ) || $extension == "") {
            $this->file_name = "$base_name" . MConst::CONFLICT_FILE_NAME;
        } else {
            $this->file_name = "$base_name" . MConst::CONFLICT_FILE_NAME . ".$extension";
        }
                                $children = MFiles::queryChildrenByParentId ($this->user_id,$this->parent_file_id );
        if ($children === false) {
            throw new MFilesException ( FXP::t ( MConst::INTERNAL_SERVER_ERROR ), MConst::HTTP_CODE_500 );
        }
        $names = array ();
        foreach ( $children as $k => $v ) {
            $names [strtolower($v ["file_name"])] = $v ["file_name"];
        }
                                $this->file_name   = MUtils::getConflictName ( $this->file_name, $names );
        $this->path        = MUtils::convertStandardPath($this->parent_path . "/" . $this->file_name);
        $this->file_path   = "/" . $this->user_id . $this->path;
        $this->create_file = true;
    }
    
    private function createFile($file_detail) {
                                if ($this->create_file == false) {
            return;
        }
        
                                $conflict_file = MFiles::queryFilesByPath ( $this->file_path, TRUE );
        if ($conflict_file != false && empty ( $conflict_file ) == false) {
            foreach ( $conflict_file as $file ) {
                                                                if ($file ["file_type"] == MConst::OBJECT_TYPE_FILE) {
                    $file_detail = MFiles::exchange2Object ( $file, TRUE);
                    $this->creatFileDeleted ( $file_detail );
                    return;
                }
            }
        }
        $this->spaceFilter ($this->size);           $file_detail->file_create_time = $this->file_update_time;
        $file_detail->file_update_time = $this->file_update_time;
        $file_detail->file_size = $this->size;
        $file_detail->file_type = MConst::OBJECT_TYPE_FILE;
        $file_detail->parent_file_id = $this->parent_file_id;
        $file_detail->version_id = $this->version_id;
        $file_detail->file_path = "/" . $this->user_id . $this->path;
        $file_detail->file_name = $this->file_name;
        $file_detail->event_uuid = MUtils::random_string ( MConst::LEN_EVENT_UUID );
                                $version = MUtils::getFileVersions ( $this->version_id, $this->action, $this->user_id, $this->user_nick );
                                $retval = MFiles::CreateFileDetail ( $file_detail, $this->user_id, $this->user_nick );
        if ($retval === false) {
            throw new MFilesException ( FXP::t ( MConst::INTERNAL_SERVER_ERROR ), MConst::HTTP_CODE_500 );
        }
                                $context = array( 
                  "hash"  => $this->file_hash,
                  "rev"   => (int)$this->version_id,
                  "bytes" => (int)$this->size);
        $retval = MEvents::CreateEvents ( $this->user_id, 
                                          $this->user_device_id,
                                          $this->action,
                                          $this->file_path,
                                          serialize($context),
                                          $file_detail->event_uuid
                                          );
        if ($retval === false) {
            throw new MFilesException ( FXP::t ( MConst::INTERNAL_SERVER_ERROR ), MConst::HTTP_CODE_500 );
        }
                if (MFileVersions::updateRefCountById ( $this->version_id ) == false) {
            throw new MFilesException ( FXP::t ( MConst::INTERNAL_SERVER_ERROR ), MConst::HTTP_CODE_500 );
        }
        $retval = MFileMetas::createFileMeta ( $this->file_path, MConst::VERSION, $version );
        if ($retval === false) {
            throw new MFilesException ( FXP::t ( MConst::INTERNAL_SERVER_ERROR ), MConst::HTTP_CODE_500 );
        }
    }
    
    private function renameFile() {
                                if ($this->overwrite == true) {
            return;
        }
        $children = MFiles::queryChildrenByParentId ($this->user_id, $this->parent_file_id );
        if ($children === false) {
            throw new MFilesException ( FXP::t ( MConst::INTERNAL_SERVER_ERROR ), MConst::HTTP_CODE_500 );
        }
        $names = array ();
        foreach ( $children as $k => $v ) {
            $names [strtolower($v ["file_name"])] = $v ["file_name"];
        }
                                $this->file_name   = MUtils::getConflictName ( $this->file_name, $names );
        $this->path        = MUtils::convertStandardPath($this->parent_path . "/" . $this->file_name);
        $this->file_path   = "/" . $this->user_id . $this->path;
        $this->create_file = true;
    }
    
    
    private function spaceFilter($size) {
        if ($this->create_file == false) {
            return ;
        }
                                $this->used_space += $size;
        if ($this->used_space > $this->space) {
            throw new MFilesException(FXP::t("User is over storage quota."), 
            MConst::HTTP_CODE_507);
        }
    }
     
    
    private function isExistThumbnail() {
        if ($this->size > MConst::MAX_IMAGE_SIZE || $this->size <= 0) {
            return false;
        }
        foreach ( MThumbnailBase::$_support_types as $value ) {
            if ($value == $this->type) {
                return true;
            }
        }
        return false;
    }
}
?>